import type { Metadata } from 'next'; import Link from 'next/link'; import { notFound } from 'next/navigation'; import { orderedSections, QuietLine, TODAY_FEED_HREF, TODAY_LABELS, TodayItemRow } from '@/components/changes/today-sections'; import { DataStrip, SectionNav } from '@/components/layout/terminal'; import { BreadcrumbLd } from '@/components/meta/breadcrumb-ld'; import { ImportanceMark } from '@/components/ui/badges'; import { EntityLink } from '@/components/ui/entity'; import { Hint } from '@/components/ui/hint'; import { Container, Note, PageHeader, Section } from '@/components/ui/section'; import { EmptyState, Unavailable } from '@/components/ui/unavailable'; import { apiD3, safe } from '@/lib/api'; import { fmtDate, fmtInt, num } from '@/lib/format'; import { routes, SITE_NAME, SITE_URL } from '@/lib/site'; type Params = { params: Promise<{ date: string }>; searchParams: Promise<{ include_backfill?: string }> }; const VALID = /^\d{4}-\d{2}-\d{2}$/; function shift(date: string, days: number): string { const d = new Date(`${date}T00:00:00Z`); d.setUTCDate(d.getUTCDate() + days); return d.toISOString().slice(0, 10); } export async function generateMetadata({ params }: Params): Promise { const { date } = await params; if (!VALID.test(date)) return { title: 'Not found', robots: { index: false } }; const title = `Today in AI — ${fmtDate(date)}`; const description = `What happened in AI on ${fmtDate(date)}: major releases, price moves, benchmark moves, model changes, research, open-weight releases, deprecations, provider and hardware changes — generated from the ${SITE_NAME} change log.`; return { title, description, alternates: { canonical: routes.changesDay(date) }, openGraph: { title: `${title} | ${SITE_NAME}`, description, url: `${SITE_URL}${routes.changesDay(date)}`, type: 'article' } }; } export default async function DailyPage({ params, searchParams }: Params) { const { date } = await params; const sp = await searchParams; if (!VALID.test(date) || Number.isNaN(new Date(`${date}T00:00:00Z`).getTime())) notFound(); const today = new Date().toISOString().slice(0, 10); if (date > today) notFound(); const backfill = sp.include_backfill === '1'; const d = await safe(apiD3.changesDaily(date, 30, backfill)); const { present, quiet } = orderedSections(d?.today); const total = num(d?.total) ?? (d ? Object.values(d.counts ?? {}).reduce((n, v) => n + (num(v) ?? 0), 0) : 0); const excluded = num(d?.backfill_excluded) ?? 0; const prev = d?.previous_day ?? shift(date, -1); const next = d?.next_day && d.next_day <= today ? d.next_day : date < today ? shift(date, 1) : null; const strip = (d?.today ?? []).filter((s) => (num(s.total) ?? 0) > 0).slice(0, 8); return ( Changes / Today in AI } title={ <> What changed in AI on {fmtDate(date)} } lede={d ? <>{fmtInt(total)} events occurred on this UTC day{d.today ? ` across ${present.length} sections` : ''} — grouped when several documents describe one release, generated from the database, nothing editorial. : undefined} aside={ } />
{!d ? ( ) : total === 0 && !d.new_models?.length && present.length === 0 ? ( {excluded > 0 ? ( <> {fmtInt(excluded)} back-filled historical events fall on this date but are not “today” news — see them on the timeline with backfill or include them here. ) : ( 'Connectors observed no material change occurring on this UTC day.' )} ) : ( <> {strip.length > 0 && ({ label: s.label ?? TODAY_LABELS[s.key] ?? s.key, value: fmtInt(s.total), href: `#${s.key.toLowerCase()}` }))} />}

Dates are when events occurred {excluded > 0 && ( {fmtInt(excluded)} back-filled historical {excluded === 1 ? 'event' : 'events'} excluded ·{' '} see them on the timeline {' '} ·{' '} {backfill ? 'hide backfill' : 'include here'} )} {backfill && including backfill}

{present.length > 1 && ({ id: s.key.toLowerCase(), label: s.label ?? TODAY_LABELS[s.key] ?? s.key }))} className="mt-3" />} {d.new_models?.length > 0 && (
{fmtInt(d.new_models.length)} new model{d.new_models.length === 1 ? '' : 's'}} hairline={false} action={{ href: `/models?year_from=${date.slice(0, 4)}&sort=release`, label: 'Models by release' }}>
    {d.new_models.slice(0, 30).map((m) => (
  • {m.organization?.name ?? ''}
  • ))}
{d.new_models.length > 30 && First 30 of {fmtInt(d.new_models.length)}.}
)} {present.map((s) => { const shown = s.items.length; const tot = num(s.total) ?? shown; const feed = TODAY_FEED_HREF[s.key]?.(date); return (
{s.label ?? TODAY_LABELS[s.key] ?? s.key} {fmtInt(tot)}} action={feed ? { href: feed, label: 'Feed' } : undefined}>
    {s.items.map((it) => ( ))}
{tot > shown && First {fmtInt(shown)} of {fmtInt(tot)}{feed ? <> — all in the feed → : null}} {s.items.some((it) => it.importance >= 3) && (

major · important · notable

)}
); })} {d.note && {d.note}} )}
); }